<react-outlet [component]="xxxx" [root]="true" #root></react-outlet>
<NgOutlet component={OutletRefTestComponent}></NgOutlet>
componentWrapper(xxxx, {}).reactFunctionComponent
componentWrapper(xxxx, {}).reactElement
<!-- 直接子組件,也就是react-outlet的子級 -->
<react-outlet [component]="xxxx" #child></react-outlet>
<!-- 非直接子組件,父級不是react-outlet,但是父級的?級有react-outlet -->
<react-outlet [component]="xxxx" [parent]="root"></react-outlet>
<xxx [parent]="root"></xxx>
react-flow
官方例子為例import { stratify, tree } from 'd3-hierarchy';
import React, { useCallback, useMemo } from 'react';
import ReactFlow, {
ReactFlowProvider,
Panel,
useNodesState,
useEdgesState,
useReactFlow,
} from 'reactflow';
import { initialNodes, initialEdges } from './nodes-edges.js';
import 'reactflow/dist/style.css';
const g = tree();
const getLayoutedElements = (nodes, edges, options) => {
if (nodes.length === 0) return { nodes, edges };
const { width, height } = document
.querySelector(`[data-id="${nodes[0].id}"]`)
.getBoundingClientRect();
const hierarchy = stratify()
.id((node) => node.id)
.parentId((node) => edges.find((edge) => edge.target === node.id)?.source);
const root = hierarchy(nodes);
const layout = g.nodeSize([width * 2, height * 2])(root);
return {
nodes: layout
.descendants()
.map((node) => ({ ...node.data, position: { x: node.x, y: node.y } })),
edges,
};
};
const LayoutFlow = () => {
const { fitView } = useReactFlow();
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onLayout = useCallback(
(direction) => {
const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(nodes, edges, {
direction,
});
setNodes([...layoutedNodes]);
setEdges([...layoutedEdges]);
window.requestAnimationFrame(() => {
fitView();
});
},
[nodes, edges]
);
return (
<ReactFlow
nodes={nodes}
edges={edges}
onNodesChange={onNodesChange}
onEdgesChange={onEdgesChange}
fitView
>
<Panel position="top-right">
<button onClick={onLayout}>layout</button>
</Panel>
</ReactFlow>
);
};
export default function () {
return (
<ReactFlowProvider>
<LayoutFlow />
</ReactFlowProvider>
);
}
<react-outlet [component]="ReactFlowProvider" [root]="true">
<react-outlet [component]="ReactFlow" #child #root [runInReact]="context">
<react-outlet
[component]="Panel"
#child
[props]="$any({ position: 'top-right' })"
>
<button #child (click)="root.output()?.['onLayout']('TB')">
vertical layout
</button>
<button #child (click)="root.output()?.['onLayout']('LR')">
horizontal layout
</button>
</react-outlet>
</react-outlet>
</react-outlet>
import { Component } from '@angular/core';
import { ReactOutlet } from '@cyia/ngx-bridge';
import ReactFlow, {
ReactFlowProvider,
Panel,
useReactFlow,
useNodesState,
useEdgesState,
} from 'reactflow';
import Dagre from '@dagrejs/dagre';
import { initialNodes, initialEdges } from './nodes-edges';
import { useCallback } from 'react';
const g = new Dagre.graphlib.Graph().setDefaultEdgeLabel(() => ({}));
const getLayoutedElements = (nodes: any, edges: any, options: any) => {
g.setGraph({ rankdir: options.direction });
edges.forEach((edge: any) => g.setEdge(edge.source, edge.target));
nodes.forEach((node: any) => g.setNode(node.id, node));
Dagre.layout(g);
return {
nodes: nodes.map((node: any) => {
const { x, y } = g.node(node.id);
return { ...node, position: { x, y } };
}),
edges,
};
};
@Component({
selector: 'app-custom-layout',
standalone: true,
imports: [ReactOutlet],
templateUrl: './custom-layout.component.html',
styleUrl: './custom-layout.component.scss',
host: { style: 'display:block;height:400px' },
})
export class CustomLayoutComponent {
ReactFlowProvider = ReactFlowProvider;
ReactFlow = ReactFlow;
Panel = Panel;
context = (props: any, output: any) => {
const { fitView } = useReactFlow();
const [nodes, setNodes, onNodesChange] = useNodesState(initialNodes);
const [edges, setEdges, onEdgesChange] = useEdgesState(initialEdges);
const onLayout = useCallback(
(direction: any) => {
const layouted = getLayoutedElements(nodes, edges, { direction });
setNodes([...layouted.nodes]);
setEdges([...layouted.edges]);
window.requestAnimationFrame(() => {
fitView();
});
},
[nodes, edges]
);
return {
props: {
nodes,
edges,
onNodesChange,
onEdgesChange,
fitView: true,
},
output: {
onLayout,
},
};
};
}
runInReact
屬性中就可以了,我們只需要在返回對象的output
中寫出導出相關方法,供給ng環境下調用ngx-bridge
在開發時還在以下庫中進行了測試,均可正常執行理論上支持所有react庫,但是無法一一測試,只是挑選了一些 star 比較高的庫進行測試